﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MacomberMapSystem.Common.Database;
using MacomberMapSystem.Common.Serialization;
using System.Data.Common;
using WeifenLuo.WinFormsUI.Docking;
using System.Xml;
using System.IO;
using MacomberMapSystem.Common.Internals;
using MacomberMapSystem.Common.Exports;
using System.Threading;
using MacomberMapSystem.Common.CIM;
using System.Drawing.Imaging;
using MacomberMapSystem.Common.Properties;
using System.Diagnostics;
using MacomberMapSystem.Common.Integration;
using System.Data.OleDb;
using System.Collections.Specialized;
using MacomberMapSystem.Common.CIM.Direct;
using MacomberMapSystem.Common.Processing;
using System.Data.SQLite;
using MacomberMapSystem.Common.User_Interfaces.Database;
using Ionic.Zip;

namespace MacomberMapSystem.Common.User_Interfaces.One_Lines
{
    /// <summary>
    /// This class allows the user to search for one-lines, and view them
    /// </summary>
    public partial class frmLocateOneLine : DockContent
    {
        #region Variable declarations
        /// <summary>Our collection of models</summary>
        public Dictionary<int, MM_Database_Model> Models;

        /// <summary>The database connector</summary>
        private MM_Database_Connector Db;

        /// <summary>The repository to be searched on demand</summary>
        private MM_Repository Repository;

        #endregion

        #region Initialization
        /// <summary>
        /// Instantiate our one-line list
        /// </summary>
        /// <param name="Db"></param>
        /// <param name="Models"></param>
        /// <param name="Repository">The data repository</param>        
        public frmLocateOneLine(MM_Repository Repository, Dictionary<int, MM_Database_Model> Models, MM_Database_Connector Db)
        {
            InitializeComponent();
            cmbOneLineType.SelectedIndex = 0;
            this.Db = Db;
            this.Repository = Repository;
            this.Models = Models;
            foreach (MM_Database_Model Mdl in Models.Values)
                if (!cmbModelCategory.Items.Contains(Mdl.ModelCategory))
                    cmbModelCategory.Items.Add(Mdl.ModelCategory);
        }
        #endregion

      

        /// <summary>
        /// When the model changes, load in all one-lines for it
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbModel_SelectedIndexChanged(object sender, EventArgs e)
        {
            cmbOneLine.Items.Clear();          
            if (cmbModel.SelectedItem != null)
            {
                MM_Database_Model SelectedModel = cmbModel.SelectedItem as MM_Database_Model;
                Dictionary<String, int> Tags = new Dictionary<string, int>();

                //Now, upload our list of one-lines depending on our type                
                cmbOneLine.Items.Add("");
                cmbOneLine.Sorted = false;
                int CurCompany = 0;
                if (cmbOneLineType.Text == "Breaker-to-Breaker")
                {
                    if (SelectedModel.EnsureOpened())
                        for (int Trace = 0; Trace < SelectedModel.Traces.Count; Trace++)
                        {
                            String TraceDesc = SelectedModel.Traces[Trace].Name + " (" + SelectedModel.Traces[Trace].Description + ")";
                            cmbOneLine.Items.Add(TraceDesc);
                            Tags.Add(TraceDesc, Trace);
                        }
                }
                else if (cmbOneLineType.Text == "Operator" && SelectedModel.State == MM_Database_Model.enumModelState.Completed)
                    foreach (CIM_Element Company in SelectedModel.ElementsOfType("cim:Company"))
                    {
                        if (Company.ParseSingle("<etx:Operatorship", null) != null)
                        {
                            cmbOneLine.Items.Add(Company);
                            Tags.Add(Company.ToString(), CurCompany);
                        }
                        CurCompany++;
                    }
                else
                    using (DbCommand dCmd = Db.CreateCommand("SELECT ID, TEID, Names FROM MM_DATABASE_ONELINE WHERE ONELINETYPE=:0 AND MODELS LIKE :1", cmbOneLineType.SelectedIndex, "%," + SelectedModel.ID.ToString() + ",%"))
                    using (DbDataReader dRd = dCmd.ExecuteReader())
                        while (dRd.Read())
                            foreach (String splStr in dRd["Names"].ToString().Split(','))
                                if (dRd["TEID"] is DBNull)
                                {
                                    cmbOneLine.Items.Add(splStr);
                                    Tags.Add(splStr, Convert.ToInt32(dRd["ID"]));
                                }
                                else
                                {
                                    int Count = 0;
                                    while (Tags.ContainsKey(splStr + (Count == 0 ? "" : " #" + Count.ToString()) + " - " + Convert.ToUInt64(dRd["TEID"]).ToString("#,##0")))
                                        Count++;
                                    String SubName = splStr + (Count == 0 ? "" : " #" + Count.ToString()) + " - " + Convert.ToUInt64(dRd["TEID"]).ToString("#,##0");
                                    cmbOneLine.Items.Add(SubName);
                                    Tags.Add(SubName, Convert.ToInt32(dRd["ID"]));
                                }
             
                cmbOneLine.Sorted = true;
                cmbOneLine.Tag = Tags;
                cmbOneLine.SelectedIndex = 0;
            }
        }

        /// <summary>
        /// When the selected one-line changes, load it in
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbOneLine_SelectedIndexChanged(object sender, EventArgs e)
        {
            Dictionary<String, int> Tags = cmbOneLine.Tag as Dictionary<String, int>;
            int ID;

            if (cmbOneLine.SelectedItem == null || !Tags.TryGetValue(cmbOneLine.Text, out ID))
                OneLinePreview.AssignOneLine(null, null, null, Repository);
            else
            {
                MM_Database_Model Model = cmbModel.SelectedItem as MM_Database_Model;
                MM_Database_OneLine OneLine;
                Image OLImg;
                if (cmbOneLineType.Text == "Breaker-to-Breaker" && Model.Traces.Count > 0)
                {
                    XmlDocument xOneLine = CIM_BreakerToBreaker.AutoGenerateOneLine(Model.Traces[ID]);
                    clsTomSawyer.RunLayout(xOneLine, Repository);
                    OneLine = new MM_Database_OneLine(null, null);
                    OneLine.Document = xOneLine;
                    OneLine.Models = new MM_Database_Model[] { Model };
                    OneLine.Names = new string[] { Model.Traces[ID].Name };
                    OneLine.ID = -1;
                    OneLine.OneLineType = MM_Database_OneLine.OneLineTypeEnum.BreakerToBreaker;
                    OneLine.rdfID = Model.Traces[ID].rdfID;
                    MM_Oneline_Export OLExport = Model.LocateExport(OneLine);
                    OLImg = MM_Image_Exporter.OneLineImage(OneLine, Model, OLExport, null);
                }
                else if (cmbOneLineType.Text == "Operator" && Tags.Count > 0)
                {
                    CIM_Element Company = Model.ElementsOfType("cim:Company")[ID];
                    XmlDocument xOneLine = CIM_BreakerToBreaker.AutoGenerateOneLine(Company);
                    clsTomSawyer.RunLayout(xOneLine, Repository);
                    OneLine = new MM_Database_OneLine(null, null);
                    OneLine.Document = xOneLine;
                    OneLine.Models = new MM_Database_Model[] { Model };
                    OneLine.Names = new string[] { Company["cim:IdentifiedObject.aliasName"] };
                    OneLine.ID = -1;
                    OneLine.OneLineType = MM_Database_OneLine.OneLineTypeEnum.Operatorship;
                    OneLine.rdfID = Company.rdfID;
                    OLImg = MM_Image_Exporter.OneLineImage(OneLine, Model, Model.LocateExport(OneLine), null);
                }                
                else
                {
                    OLImg = Db.LoadOneLineImage(ID);
                    OneLine = Db.LoadOneLine(ID, Repository);
                }
                OneLinePreview.AssignOneLine(OneLine, OLImg, Model, Repository);
            }
        }
        
        /// <summary>
        /// Write out a line for our element
        /// </summary>
        /// <param name="Trace"></param>
        /// <param name="Elem"></param>
        /// <param name="sW"></param>
        private void WriteElementLine(CIM_Trace Trace, CIM_Element Elem, StreamWriter sW)
        {
            List<String> OutString = new List<string>();

            //Write our trace information
            if (Trace != null)
            {
                OutString.Add("\"" + Trace.Name + "\"");
                OutString.Add("\"" + Trace.Description + "\"");
                OutString.Add(Trace.Radial.ToString());
            }
            else
                OutString.AddRange(",,".Split(','));


            //Write our substation
            if (Elem.TypeName == "cim:ACLineSegment")
                OutString.Add("\"" + MM_Type_Converter.TitleCase(Elem.ACSegmentStations[0].Name) + " to " + MM_Type_Converter.TitleCase(Elem.ACSegmentStations[1].Name) + "\"");
            else if (Elem.TypeName == "cim:SeriesCompensator")
                OutString.Add("\"" + MM_Type_Converter.TitleCase(Elem.ACSegmentStations[0].Name) + "\"");
            else
                OutString.Add("\"" + MM_Type_Converter.TitleCase(Elem.Substation.Name) + "\"");

            OutString.Add("\"" + Elem.ElemType + "\"");
            OutString.Add("\"" + MM_Type_Converter.TitleCase(Elem.LineName) + "\"");
            OutString.Add("\"" + Elem.rdfID.ToString() + "\"");
            if (Elem.VoltageLevel != null)
                OutString.Add("\"" + MM_Type_Converter.TitleCase(Elem.VoltageLevel.Name) + "\"");
            else
                OutString.Add("");
            OutString.Add(Elem.TEID);
            OutString.Add(Elem["etx:Equipment.psseid"]);

            CIM_Element[] Nodes = Elem.TypeName == "cim:ConnectivityNode" ? new CIM_Element[] { Elem } : Elem.Nodes;
            OutString.Add(Nodes[0]["etx:ConnectivityNode.PSSEBusNumber"]);

            if (Nodes.Length > 1 && Nodes[0] != Nodes[1])
                OutString.Add(Nodes[1]["etx:ConnectivityNode.PSSEBusNumber"]);

            sW.WriteLine(String.Join(",", OutString.ToArray()));
        }

   
     
        
        /// <summary>
        /// Refresh our collection of models
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRefresh_Click(object sender, EventArgs e)
        {
            cmbModel.SelectedIndex = -1;
            cmbModel.Items.Clear();
            new MM_Login_Process("Loading substations", Repository.LoadModels).Invoke();
            foreach (MM_Database_Model Mdl in Models.Values)
                if (!cmbModelCategory.Items.Contains(Mdl.ModelCategory))
                    cmbModelCategory.Items.Add(Mdl.ModelCategory);
        }

        /// <summary>
        /// Select a model by date
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelect_Click(object sender, EventArgs e)
        {
            using (frmSelectModel SelModel = new frmSelectModel(Repository))
                if (SelModel.ShowDialog() == DialogResult.OK)
                {
                    cmbModelCategory.SelectedItem = SelModel.SelectedModel.ModelCategory;
                    cmbModel.SelectedItem = SelModel.SelectedModel;
                }
        }


        /// <summary>
        /// Update our current selection of models
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbModelCategory_SelectedIndexChanged(object sender, EventArgs e)
        {
            cmbModel.Items.Clear();
            SortedDictionary<int, MM_Database_Model> SortedModels = new SortedDictionary<int, MM_Database_Model>();
            foreach (MM_Database_Model Model in this.Models.Values)
                if (Model.ModelCategory == cmbModelCategory.Text)
                    SortedModels.Add(-Model.ID, Model);
            cmbModel.Items.AddRange(SortedModels.Values.ToArray());
        }

        /// <summary>
        /// Audit one-line completion for our model
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAudit_Click(object sender, EventArgs e)
        {
            if (cmbModel.SelectedItem == null)
                return;
            WeifenLuo.WinFormsUI.Docking.DockPanel TargetPanel = null;
            Form FormToCheck = this.ParentForm;
            do
            {
                foreach (Control ctl in FormToCheck.Controls)
                    if (ctl is WeifenLuo.WinFormsUI.Docking.DockPanel)
                        TargetPanel = ctl as WeifenLuo.WinFormsUI.Docking.DockPanel;
                FormToCheck = FormToCheck.ParentForm;
            } while (TargetPanel == null && FormToCheck != null);

            new frmOneLineAudit(cmbModel.SelectedItem as MM_Database_Model, Repository.Db).Show(TargetPanel);
        }
       
    }
}